using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Practices.ServiceLocation;
using System.Web.Mvc;

using MvcCms.Core;
using MvcCms.Data;
using MvcCms.Data.Entities;
using MvcCms.Service.Cache;
using MvcCms.Service.Code;
using MvcCms.Service.Validation;
using MvcCms.Core.Interfaces;
using MvcCms.Service.Logging;
using System.Web.Routing;
using System.Threading;

namespace MvcCms.Service.CMSCode
{
    public class CmsService : ICmsService
    {
        #region Constructors

        private readonly ICacheService _cacheService;
        private readonly Portal _currentPortal;
        private readonly ICmsRepository _repository;
        public IValidationDictionary _validationDictionary;
        private readonly IMvcCmsValidation _mvccmsValidationService;

        public CmsService(IValidationDictionary validationDictionary, ICmsRepository repository,
                           ICacheService cacheService, IMvcCmsValidation mvcCmsValidation)
        {
            _validationDictionary = validationDictionary;
            _repository = repository;
            if (cacheService != null)
            {
                _currentPortal = cacheService.GetCurrentPortal();
            }
            _cacheService = cacheService;
            _mvccmsValidationService = mvcCmsValidation;
        }

        #endregion

        public ModelStateDictionary GetModelStateDictionary()
        {
            return ((MvcCms.Service.Validation.ModelStateWrapper)_validationDictionary)._modelState;
        }

        #region Validation Methods

        private bool ValidateModule(Module widgetToValidate)
        {
            if (widgetToValidate.Title.Trim().Length == 0)
                _validationDictionary.AddError("Title", "Title is required.");
            if (widgetToValidate.AddedDate.ToString().Trim().Length == 0)
                _validationDictionary.AddError("AddedDate", "AddedDate is required.");
            if (widgetToValidate.Active.ToString().Trim().Length == 0)
                _validationDictionary.AddError("Active", "Active is required.");
            if (widgetToValidate.Importance.ToString().Trim().Length == 0)
                _validationDictionary.AddError("Importance", "Importance is required.");
            if (widgetToValidate.Portal == null)
                _validationDictionary.AddError("", "Portal is required.");

            return _validationDictionary.IsValid;
        }

        private bool ValidateRedirect(Redirect redirectToValidate)
        {
            if (redirectToValidate.OldPage.Trim().Length == 0)
                _validationDictionary.AddError("OldPage", "OldPage is required.");
            if (redirectToValidate.NewPage.ToString().Trim().Length == 0)
                _validationDictionary.AddError("NewPage", "NewPage is required.");
            return _validationDictionary.IsValid;
        }

        private bool ValidateCategory(ContentCategory categoryToValidate)
        {
            string message = "";
            if (!_mvccmsValidationService.ValidateCategory(categoryToValidate, ref message))
            {
                _validationDictionary.AddError("Title", message);
            }
            string pathTemp = "," + categoryToValidate.SinglePath.ToLower() + ",";
            //skip below for unit testing
            if (HttpContext.Current != null && !categoryToValidate.UsesCustomAreaRoute)
            {
                if (HttpContext.Current.Application["ReservedPathNames"].ToString().ToLower().Contains(pathTemp))
                {
                    _validationDictionary.AddError("Title", "The title entered is being used by the system, please revise.");
                }
            }

            if (categoryToValidate.Title.Trim().Length == 0)
                _validationDictionary.AddError("Title", "Title is required.");
            if (categoryToValidate.Portal == null)
                _validationDictionary.AddError("", "Portal is required.");

            if (categoryToValidate.Path.Trim().Length == 0)
            {
                _validationDictionary.AddError("", "The title you entered was not able to be converted to a valid url path.  Please try again.");
            }

            return _validationDictionary.IsValid;
        }

        private bool ValidatePage(ContentPage pageToValidate)
        {
            if (pageToValidate.Portal == null)
                _validationDictionary.AddError("", "Portal is required.");

            string message = "";
            if (!_mvccmsValidationService.ValidatePage(pageToValidate, ref message))
            {
                _validationDictionary.AddError("Title", message);
            }
            string pathTemp = "," + pageToValidate.Path.ToLower() + ",";
            //skip below for unit testing
            if (HttpContext.Current != null)
            {
                if (HttpContext.Current.Application["ReservedPathNames"].ToString().ToLower().Contains(pathTemp) && pageToValidate.ContentPageID == 0)
                {
                    _validationDictionary.AddError("Title", "The title entered is being used by the system, please revise.");
                }
            }
            if (pageToValidate.Title.Trim().Length == 0)
            {
                _validationDictionary.AddError("Title", "Title is required.");
            }

            if (pageToValidate.Path.Trim().Length == 0)
            {
                _validationDictionary.AddError("Title", "The title you entered was not able to be converted to a valid url path.  Please try again.");
            }

            return _validationDictionary.IsValid;
        }

        private bool ValidateComment(ContentComment commentToValidate)
        {
            if (commentToValidate.Body.Trim().Length == 0)
                _validationDictionary.AddError("Body", "Body is required.");

            return _validationDictionary.IsValid;
        }

        #endregion

        #region Module Methods

        public Module GetModule(int widgetId)
        {
            return _repository.GetModule(widgetId);
        }

        private IEnumerable<WeightedContentModule> ListWeightedContentModulesByTargetDiv(Portal currentPortal, string targetDiv, bool isAuthenticated)
        {
            var modules = _cacheService.ListWeightedContentModules()
                .Where(wcm => wcm.WeightedContent.PortalID == currentPortal.PortalID &&
                    wcm.WeightedContent.TargetDiv == targetDiv);

            if (isAuthenticated)
            {
                return modules.Where(m => m.HideIfAuthenticated.Equals(false)).ToList();
            }
            else
            {
                return modules.ToList();
            }
        }

        public WeightedContentModule GetNextWeightedModuleForTargetDiv(string targetDiv, bool isAuthenticated, string[] roles, int lastWeightedModuleId)
        {
            var modulesToChooseFrom = ListWeightedContentModulesByTargetDiv(_currentPortal, targetDiv, isAuthenticated);

            if (modulesToChooseFrom.Count() > 1 && lastWeightedModuleId > 0)
            {
                modulesToChooseFrom = modulesToChooseFrom.Where(m => m.ModuleID != lastWeightedModuleId);
            }

            var modulesAllowed = new List<WeightedContentModule>();
            if (modulesToChooseFrom.Count() > 0)
            {
                foreach (var module in modulesToChooseFrom)
                {
                    if (!module.ShowOnlyForRolesEnabled)
                    {
                        modulesAllowed.Add(module);
                    }
                    else
                    {
                        var roleMatch = from r in module.AllowedRoles
                                        where roles.Contains(r.RoleName)
                                        select r;
                        if (roleMatch != null)
                        {
                            modulesAllowed.Add(module);
                        }
                    }
                }

            }

            return WeightedContentManager.GetNextRandomModuleWithWeightedRatio(modulesAllowed);
        }

        private IEnumerable<WeightedContentWidget> ListWeightedContentWidgetsByZone(Portal currentPortal, string zoneName, bool isAuthenticated)
        {
            var widgets = _cacheService.ListWeightedContentWidgets()
                           .Where(wcw => wcw.WeightedContent.PortalID == currentPortal.PortalID &&
                               wcw.WeightedContent.ZoneName.ToLower() == zoneName.ToLower());

            if (isAuthenticated)
            {
                return widgets.Where(m => m.HideIfAuthenticated.Equals(false)).ToList();
            }
            else
            {
                return widgets;
            }
        }

        public WeightedContentWidget GetNextWeightedWidgetForZone(string zoneName, bool isAuthenticated, string[] roles)
        {
            var widgetsToChooseFrom = ListWeightedContentWidgetsByZone(_currentPortal, zoneName, isAuthenticated);

            var widgetsAllowed = new List<WeightedContentWidget>();
            if (widgetsToChooseFrom.Count() > 0)
            {
                foreach (var widget in widgetsToChooseFrom)
                {
                    if (!widget.ShowOnlyForRolesEnabled)
                    {
                        widgetsAllowed.Add(widget);
                    }
                    else
                    {
                        var roleMatch = from r in widget.AllowedRoles
                                        where roles.Contains(r.RoleName)
                                        select r;
                        if (roleMatch != null)
                        {
                            widgetsAllowed.Add(widget);
                        }
                    }
                }

            }
            return WeightedContentManager.GetNextRandomWidgetWithWeightedRatio(widgetsAllowed);
        }

        private IEnumerable<WeightedContentWidget> ListWeightedContentWidgetsByTargetDiv(Portal currentPortal, string targetDiv, bool isAuthenticated)
        {
            var widgets = _cacheService.ListWeightedContentWidgets()
                           .Where(wcw => wcw.WeightedContent.PortalID == currentPortal.PortalID && wcw.WeightedContent.TargetDiv == targetDiv);
            if (isAuthenticated)
            {
                return widgets.Where(m => m.HideIfAuthenticated.Equals(false)).ToList();
            }
            else
            {
                return widgets;
            }
        }

        public WeightedContentWidget GetNextWeightedWidgetForTargetDiv(string targetDiv, bool isAuthenticated, string[] roles)
        {
            var widgetsToChooseFrom = ListWeightedContentWidgetsByTargetDiv(_currentPortal, targetDiv, isAuthenticated);

            var widgetsAllowed = new List<WeightedContentWidget>();
            if (widgetsToChooseFrom.Count() > 0)
            {
                foreach (var widget in widgetsToChooseFrom)
                {
                    if (!widget.ShowOnlyForRolesEnabled)
                    {
                        widgetsAllowed.Add(widget);
                    }
                    else
                    {
                        var roleMatch = from r in widget.AllowedRoles
                                        where roles.Contains(r.RoleName)
                                        select r;
                        if (roleMatch != null)
                        {
                            widgetsAllowed.Add(widget);
                        }
                    }
                }

            }
            return WeightedContentManager.GetNextRandomWidgetWithWeightedRatio(widgetsAllowed);
        }
        public Widget GetWidget(int widgetId)
        {
            return _repository.GetWidget(widgetId);
        }
        public WeightedContent GetWeightedContent(int weightedContentId)
        {
            return _repository.GetWeightedContent(weightedContentId);
        }
        public bool CreateModule(Module widgetToCreate)
        {

            var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();

            widgetToCreate.Portal = portalRepository.GetPortal(_currentPortal.PortalID);

            // Validation logic
            if (!ValidateModule(widgetToCreate))
                return false;

            // Database logic
            try
            {
                _repository.CreateModule(widgetToCreate);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }
        public bool CreateWidget(Widget widgetToCreate)
        {
            var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();
            widgetToCreate.Portal = portalRepository.GetPortal(_currentPortal.PortalID);

            // Database logic
            try
            {
                _repository.CreateWidget(widgetToCreate);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }
        public bool CreateWeightedContent(WeightedContent weightedContentToCreate)
        {
            var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();
            weightedContentToCreate.Portal = portalRepository.GetPortal(_currentPortal.PortalID);

            // Database logic
            try
            {
                _repository.CreateWeightedContent(weightedContentToCreate);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }
        public IEnumerable<Module> ListModules()
        {
            return _repository.ListModules(_currentPortal);
        }
        public IEnumerable<Widget> ListWidgets()
        {
            return _repository.ListWidgets(_currentPortal);
        }
        public IEnumerable<WeightedContent> ListWeightedContents()
        {
            return _repository.ListWeightedContents(_currentPortal);
        }
        public IEnumerable<WeightedContentModule> ListWeightedContentModules()
        {
            return _repository.ListWeightedContentModules(_currentPortal);
        }
        public IEnumerable<DTOModule> ListModulesForPage(int pageId)
        {
            return _repository.ListModulesForPage(pageId, _currentPortal);
        }
        public IEnumerable<Widget> ListWidgetsForPage(int pageId)
        {
            return _repository.ListWidgetsForPage(pageId, _currentPortal);
        }
        public IEnumerable<Widget> ListWidgetsForZones()
        {
            return _repository.ListWidgetsForZones(_currentPortal);
        }
        public bool DeleteModule(int widgetId)
        {
            try
            {
                _repository.DeleteModule(widgetId);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }
        public bool DeleteWidget(int widgetId)
        {
            try
            {
                _repository.DeleteWidget(widgetId);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }
        public bool DeleteWeightedContent(int weightedContenttId)
        {
            try
            {
                _repository.DeleteWeightedContent(weightedContenttId);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }
        public bool EditModule(Module widgetToEdit)
        {
            var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();


            widgetToEdit.Portal = portalRepository.GetPortal(_currentPortal.PortalID);

            // Validation logic
            if (!ValidateModule(widgetToEdit))
                return false;

            // Database logic
            try
            {
                _repository.EditModule(widgetToEdit);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }
        public bool EditWidget(Widget widgetToEdit)
        {
            var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();
            widgetToEdit.Portal = portalRepository.GetPortal(_currentPortal.PortalID);

            // Database logic
            try
            {
                _repository.EditWidget(widgetToEdit);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }
        public bool EditWeightedContent(WeightedContent weightedContentToEdit)
        {
            var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();
            weightedContentToEdit.Portal = portalRepository.GetPortal(_currentPortal.PortalID);

            // Database logic
            try
            {
                _repository.EditWeightedContent(weightedContentToEdit);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }
        #endregion

        #region Content Category Methods

        public IEnumerable<ContentCategory> BuildCategoryListForBackOffice(IEnumerable<ContentCategory> categories)
        {
            return categories.Where(cat => cat.UsesCustomAreaRoute.Equals(false)).OrderBy(cat => cat.Path);
        }

        public ContentCategory GetContentCategory(int id)
        {
            return _repository.GetContentCategory(id);
        }

        public ContentCategory GetContentCategory(int id, string direction, bool issubcat)
        {
            return _repository.GetContentCategory(id, direction, issubcat, _currentPortal);
        }

        public int CreateContentCategory(ContentCategory categoryToCreate)
        {

            var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();

            categoryToCreate.Portal = portalRepository.GetPortal(_currentPortal.PortalID);

            // Validation logic
            int categoryId;
            if (!ValidateCategory(categoryToCreate))
                return 0;

            // Database logic
            try
            {

                var miscRepsoitory = ServiceLocator.Current.GetInstance<IMiscRepository>();

                categoryId = _repository.CreateContentCategory(categoryToCreate);
                _cacheService.ClearCategories();
                categoryToCreate = GetContentCategory(categoryId);

                var bodyText = categoryToCreate.Title + " Content Goes Here";
                if (categoryToCreate.UsesCustomAreaRoute) { bodyText = "N/A This is a custom area route, content here is not displayed."; }
                var newPage = new ContentPage
                {
                    Body = bodyText,
                    Title = categoryToCreate.Title + " Category",
                    Description = categoryToCreate.Title + " description",
                    Summary = categoryToCreate.Title + " published version",
                    Importance = 1,
                    AddedDate = DateTime.Now,
                    UpdateDate = DateTime.Now,
                    Approved = true,
                    ShowContributorLink = false,
                    Listed = true,
                    CommentsEnabled = false,
                    AnonCommentsEnabled = false,
                    OnlyForMembers = false,
                    OnlyForPayingMembers = false,
                    ViewCount = 0,
                    Votes = 0,
                    TotalRating = 0,
                    ReleaseDate = DateTime.Now,
                    ExpireDate = DateTime.Parse("12/12/2012"),
                    IsCategoryPage = true,
                    Contributor = categoryToCreate.Editor,
                    Editor = categoryToCreate.Editor,
                    ContentCategory = categoryToCreate,
                    IsSubPage = false,
                    Language = miscRepsoitory.GetLanguage(_currentPortal.DefaultLanguage.LanguageID)
                };
                newPage.AddedDate = DateTime.Now;
                CreateContentPage(newPage);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return 0;
            }
            return categoryId;
        }

        public bool CreateContentCategory(ContentCategory categoryToCreate, Portal newPortal)
        {
            categoryToCreate.Path = categoryToCreate.Title.ToUrlFormat();
            categoryToCreate.SinglePath = categoryToCreate.Title.ToUrlFormat();
            categoryToCreate.Portal = newPortal;

            // Database logic
            try
            {
                var miscRepsoitory = ServiceLocator.Current.GetInstance<IMiscRepository>();

                var categoryId = _repository.CreateContentCategory(categoryToCreate);
                _cacheService.ClearCategories();
                categoryToCreate = GetContentCategory(categoryId);
                var newPage = new ContentPage
                {
                    Body = categoryToCreate.Title + " Content Goes Here",
                    Title = categoryToCreate.Title + " Category",
                    Description = categoryToCreate.Title + " description",
                    Summary = categoryToCreate.Title + " published version",
                    Importance = 1,
                    AddedDate = DateTime.Now,
                    UpdateDate = DateTime.Now,
                    Approved = true,
                    ShowContributorLink = false,
                    Listed = true,
                    CommentsEnabled = false,
                    AnonCommentsEnabled = false,
                    OnlyForMembers = false,
                    OnlyForPayingMembers = false,
                    ViewCount = 0,
                    Votes = 0,
                    TotalRating = 0,
                    ReleaseDate = DateTime.Now,
                    ExpireDate = DateTime.Parse("12/12/2012"),
                    IsCategoryPage = true,
                    Contributor = categoryToCreate.Editor,
                    Editor = categoryToCreate.Editor,
                    ContentCategory = categoryToCreate,
                    IsSubPage = false,
                    Language = miscRepsoitory.GetLanguage(_currentPortal.DefaultLanguage.LanguageID),
                    Portal = newPortal
                };
                newPage.AddedDate = DateTime.Now;
                CreateContentPage(newPage, true);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public IEnumerable<ContentCategory> ListCategories()
        {
            return _repository.ListCategories(_currentPortal);
        }

        public IEnumerable<ContentCategory> ListAllCategories()
        {
            var categories = _repository.ListAllCategories();
            return categories.OrderByDescending(cat => cat.NumberOfParents);
        }
        public IEnumerable<ContentCategory> ListAllCategoriesWithPages()
        {
            var categories = _repository.ListAllCategoriesWithPages();
            return categories.OrderByDescending(cat => cat.NumberOfParents);
        }
        public IEnumerable<ContentCategory> ListCategoriesForBackOffice()
        {
            return _repository.ListCategoriesForBackOffice(_currentPortal);
        }

        public IList<ContentCategory> ListCategoriesHierarchy()
        {
            return _cacheService.ListCategoriesHierarchy();
        }

        public IEnumerable<DTOSubCategory> ListSubCategories(int catId)
        {
            return _repository.ListSubCats(catId);
        }

        public IEnumerable<ContentCategory> ListTopNav()
        {
            return _cacheService.ListTopNav();
        }
        public bool EditContentCategoryNoValidation(ContentCategory categoryToEdit)
        {
            //sometimes we don't want to validate if we are editing the descriptive properties of a reserved category like home
            var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();
            categoryToEdit.Portal = portalRepository.GetPortal(_currentPortal.PortalID);
            // Database logic
            try
            {
                _repository.EditContentCategory(categoryToEdit);
                _cacheService.ClearCategories();
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }
        public bool EditContentCategory(ContentCategory categoryToEdit)
        {
            var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();

            categoryToEdit.Portal = portalRepository.GetPortal(_currentPortal.PortalID);

            // Validation logic
            if (!ValidateCategory(categoryToEdit))
                return false;

            // Database logic
            try
            {
                _repository.EditContentCategory(categoryToEdit);
                _cacheService.ClearCategories();
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public bool DeleteContentCategory(ContentCategory categoryToDelete)
        {
            try
            {
                _repository.DeleteContentCategory(categoryToDelete);
                _cacheService.ClearCategories();
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        #endregion

        #region Content Page Methods

        public ContentPage GetContentPageForRequest()
        {
            //Default to the home category route
            int categoryId = 1;

            ContentPage contentPage = null;
            var currentRoute = RouteTable.Routes.GetRouteData(new HttpContextWrapper(HttpContext.Current));
            //if this is an area then just return null
            object oIsArea;
            currentRoute.DataTokens.TryGetValue("area", out oIsArea);
            if (oIsArea != null) { return contentPage; }
            object oCategoryId;
            currentRoute.DataTokens.TryGetValue("contentcatid", out oCategoryId);
            if (oCategoryId == null) { return contentPage; }

            var key = "__RequestedPage_" + Thread.CurrentContext.ContextID.ToString();
            var thePageThreadData = Thread.GetNamedDataSlot(key);
            if (thePageThreadData != null)
            {
                var thePage = Thread.GetData(thePageThreadData);
                if (thePage != null) { return (ContentPage)thePage; }
            }

            var fullPath = HttpContext.Current.Request.Url.AbsolutePath.ToLower();

            var path = string.Empty;
            int parentPageId = 0;
            string languagePathId = string.Empty;

            var pathValue = currentRoute.Values["path"];
            if (pathValue != null) { path = pathValue.ToString(); }

            categoryId = int.Parse(oCategoryId.ToString());

            object oParentPageId;
            currentRoute.DataTokens.TryGetValue("parentpageid", out oParentPageId);
            if (oParentPageId != null) { parentPageId = int.Parse(oParentPageId.ToString()); }
            object oLanguagePathId;
            currentRoute.DataTokens.TryGetValue("languagepathid", out oLanguagePathId);
            if (oLanguagePathId != null) { languagePathId = oLanguagePathId.ToString(); }

            key = "__PageTitle_" + Thread.CurrentContext.ContextID.ToString();
            var pageTitleThreadData = Thread.GetNamedDataSlot(key);
            if (pageTitleThreadData == null)
            {
                pageTitleThreadData = Thread.AllocateNamedDataSlot(key);
            }

            var redirKey = "__Make301Redir_" + Thread.CurrentContext.ContextID.ToString();
            var redirectThreadData = Thread.GetNamedDataSlot(key);
            if (redirectThreadData == null)
            {
                redirectThreadData = Thread.AllocateNamedDataSlot(key);
            }
            Thread.SetData(redirectThreadData, false);

            if (parentPageId != 0)
            {
                contentPage = GetAltLanguagePageForCMS(languagePathId, parentPageId);
                Thread.SetData(pageTitleThreadData, contentPage.ContentCategory.Title + " - " + contentPage.Title);
            }
            else
            {
                if (!string.IsNullOrEmpty(path))
                {
                    //check if this is a subcategory  pass in the full path and check it against
                    //this portals categories full path value
                    contentPage = GetPublishedSubCategoryContentPage(fullPath);

                    if (contentPage == null)
                    {
                        //is this is a subpage?
                        contentPage = GetContentSubPageByPath(path, categoryId);
                        if (contentPage != null)
                        {
                            Thread.SetData(pageTitleThreadData, contentPage.ContentCategory.Title + " - " + contentPage.Title);
                        }
                        else
                        {
                            Thread.SetData(redirectThreadData, true);
                        }
                    }
                    else
                    {
                        Thread.SetData(pageTitleThreadData, contentPage.ContentCategory.Title + " - " + contentPage.Title);
                    }
                }
                else
                {
                    contentPage = GetPublishedCategoryContentPage(categoryId);
                    if (contentPage == null)
                    {
                        Thread.SetData(redirectThreadData, true);
                    }
                    Thread.SetData(pageTitleThreadData, contentPage.ContentCategory.Title);
                }
            }
            if (thePageThreadData == null)
            {
                thePageThreadData = Thread.AllocateNamedDataSlot(key);
            }
            Thread.SetData(thePageThreadData, contentPage);
            return contentPage;
        }

        public ContentPage GetContentPage(int id)
        {
            return _repository.GetContentPage(id);
        }
        public DTOPage GetAltLanguagePage(int languageId, int parentPageId)
        {
            return _repository.GetAltLanguagePage(languageId, parentPageId);
        }
        public ContentPage GetAltLanguagePageForCMS(string languagePathId, int parentPageId)
        {
            return _repository.GetAltLanguagePageForCMS(languagePathId, parentPageId);
        }
        public ContentPage GetContentPage(int id, string direction)
        {
            return _repository.GetContentPage(id, direction);
        }

        public DTOPage GetDTOContentPage(int id)
        {
            return _repository.GetDTOContentPage(id);
        }

        public ContentPage GetPublishedCategoryContentPage(int catId)
        {
            return _cacheService.GetPublishedCategoryContentPage(catId);
        }

        public DTOPage GetCurrentPageForCategory(int catId)
        {
            return _repository.GetCurrentPageForCategory(catId);
        }

        public ContentPage GetContentSubPageByPath(string path, int catid)
        {
            return _cacheService.GetContentSubPageByPath(path, catid);

        }

        public ContentPage GetPublishedSubCategoryContentPage(string path)
        {
            return _cacheService.GetPublishedSubCategoryContentPage(path);
        }
        /// <summary>
        /// Lists Pages for a given portal supplied at service
        /// </summary>
        public IEnumerable<DTOContentPageForEditor> ListPages()
        {
            return _repository.ListPages(_currentPortal.PortalID).OrderBy(page => page.Title);
        }

        public IEnumerable<DTOPage> ListPagesForCategory(int catId)
        {
            return _repository.ListPagesForCategory(catId);
        }

        public IEnumerable<DTOPage> ListUnpublishedPagesForCategory(int catId)
        {
            return _repository.ListUnpublishedPagesForCategory(catId);
        }

        /// <summary>
        /// Lists Pages for a given contributor
        /// </summary>
        public IEnumerable<DTOContentPageForEditor> ListPages(Guid contributorId)
        {
            return _repository.ListPages(contributorId).OrderBy(page => page.Title);
        }

        private IEnumerable<DTOComment> ListContentCommentReplies(int commentId)
        {
            var replies = _repository.ListContentCommentReplies(commentId);

            var dtoComments = new List<DTOComment>();
            foreach (var comment in replies)
            {
                var newComment = new DTOComment
                {
                    AddedByAnonEmail = GeneralMethods.GetAddedByAvatarUrl(comment),
                    AddedByAnonName = comment.AddedByAnonName,
                    AddedDate = comment.AddedDate,
                    ElapsedTime = comment.AddedDate.ToTimeSinceString(),
                    Body = comment.Body.ConvertUrlsToLinks(),
                    CommentID = comment.CommentID,
                    ParentCommentID = comment.ParentCommentID,
                    Replies = ListContentCommentReplies(comment.CommentID),
                    Email = comment.Email,
                    UserID = comment.UserID,
                    UserName = comment.UserName.ToProfileLink(),
                    AddedByID = comment.AddedByID
                };

                dtoComments.Add(newComment);
            }
            return dtoComments;
        }
        public IEnumerable<ContentComment> ListContentComments(Guid userId)
        {
            return _repository.ListContentComments(userId);
        }
        public IEnumerable<DTOComment> ListContentComments(int pageId)
        {
            var comments = _repository.ListContentComments(pageId);

            IList<DTOComment> dtoComments = new List<DTOComment>();
            foreach (var comment in comments)
            {
                var newComment = new DTOComment
                {
                    AddedByAnonEmail = GeneralMethods.GetAddedByAvatarUrl(comment),
                    AddedByAnonName = comment.AddedByAnonName,
                    AddedDate = comment.AddedDate,
                    ElapsedTime = comment.AddedDate.ToTimeSinceString(),
                    Body = comment.Body.ConvertUrlsToLinks(),
                    CommentID = comment.CommentID,
                    ParentCommentID = comment.ParentCommentID,
                    Replies = ListContentCommentReplies(comment.CommentID),
                    Email = comment.Email,
                    UserID = comment.UserID,
                    UserName = comment.UserName.ToProfileLink(),
                    AddedByID = comment.AddedByID
                };

                dtoComments.Add(newComment);
            }
            return dtoComments;
        }

        public ContentComment GetContentComment(int commentId)
        {
            return _repository.GetContentComment(commentId);
        }

        public IEnumerable<ContentPage> ListCategoryPagesByCategory(int catId)
        {
            return _repository.ListCategoryPagesByCategory(catId, _currentPortal);
        }

        public IEnumerable<ContentPage> ListSubPages(int catId)
        {
            return _cacheService.ListSubPages(catId);
        }

        public IEnumerable<ContentPage> ListAltLanguagePages(int parentPageId)
        {
            return _cacheService.ListAltLanguagePages(parentPageId);
        }

        public bool EditContentPage(ContentPage pageToEdit, string newTitle)
        {
            //Apply Business Rules
            var newPath = newTitle.ToUrlFormat();
            var oldPath = pageToEdit.Title.ToUrlFormat();
            if (newPath != oldPath)
            {
                //lets make a 301 redirect
                var protocol = "http://";
                if (HttpContext.Current.Request.IsSecureConnection) { protocol = "https://"; }
                var catPath = pageToEdit.ContentCategory.Path;
                //let's make one and for now send it to the not found page
                var redirect = new Redirect
                {
                    Description = "Auto Generated By MvcCms",
                    NewPage = protocol + _currentPortal.URLAuthority + "/" + catPath + "/" + newPath,
                    OldPage = protocol + _currentPortal.URLAuthority + "/" + catPath + "/" + oldPath
                };
                CreateRedirect(redirect);
                pageToEdit.Title = newTitle;
            }
            return EditContentPage(pageToEdit);
        }
        public bool EditContentPage(ContentPage pageToEdit)
        {
            var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();
            pageToEdit.Portal = portalRepository.GetPortal(_currentPortal.PortalID);

            //Apply Business Rules
            pageToEdit.Path = pageToEdit.Title.ToUrlFormat();

            // Validation logic
            if (!ValidatePage(pageToEdit))
                return false;

            // Database logic
            try
            {
                _repository.EditContentPage(pageToEdit);
                _cacheService.ClearCategories();
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public bool EditContentComment(ContentComment contentcommentToEdit)
        {
            // Validation logic
            if (!ValidateComment(contentcommentToEdit))
                return false;

            // Database logic
            try
            {
                _repository.EditContentComment(contentcommentToEdit);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public bool DeleteContentPage(ContentPage pageToDelete)
        {
            try
            {
                _repository.DeleteContentPage(pageToDelete);
                _cacheService.ClearCategories();
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public bool DeleteContentComment(ContentComment commentToDelete)
        {
            try
            {
                _repository.DeleteContentComment(commentToDelete);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public bool SetPublishedPage(int contentPageId)
        {
            try
            {
                _repository.SetPublishedPage(contentPageId);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public int CreateContentPage(ContentPage contentpageToCreate)
        {
            var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();
            var portal = portalRepository.GetPortal(_currentPortal.PortalID);
            contentpageToCreate.Portal = portal;

            //Apply Business Rules
            contentpageToCreate.Path = contentpageToCreate.Title.ToUrlFormat();
            //if the page language is not set set it to the portal default
            if (contentpageToCreate.Language == null)
            {
                contentpageToCreate.Language = portal.DefaultLanguage;
            }
            //set the initial importance of the page
            if (!contentpageToCreate.Importance.HasValue)
            {
                var subPages = ListSubPages(contentpageToCreate.ContentCategory.CategoryID).OrderByDescending(page => page.Importance);
                if (subPages.Count() > 0)
                {
                    foreach (var subPage in subPages)
                    {
                        contentpageToCreate.Importance = subPage.Importance + 1;
                        break;
                    }
                }
                else
                {
                    contentpageToCreate.Importance = 1;
                }
            }
            // Validation logic
            int pageid;
            if (!ValidatePage(contentpageToCreate))
                return 0;

            // Database logic
            try
            {
                pageid = _repository.CreateContentPage(contentpageToCreate);
                _cacheService.ClearCategories();
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return 0;
            }
            return pageid;
        }

        private void CreateContentPage(ContentPage contentpageToCreate, bool fromCreatePortal)
        {
            //Apply Business Rules
            contentpageToCreate.Path = contentpageToCreate.Title.ToUrlFormat();

            // Validation logic
            if (!ValidatePage(contentpageToCreate))
                return;

            // Database logic
            try
            {
                _repository.CreateContentPage(contentpageToCreate);
                _cacheService.ClearCategories();
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return;
            }
            return;
        }

        public bool CreateContentComment(ContentComment contentcommentToCreate)
        {
            // Business Rules logic
            contentcommentToCreate.Body = HttpUtility.HtmlEncode(contentcommentToCreate.Body).ToComment();

            // Validation logic
            if (!ValidateComment(contentcommentToCreate))
                return false;

            // Database logic
            try
            {
                _repository.CreateContentComment(contentcommentToCreate);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        #endregion

        #region Redirect Methods
        public IEnumerable<Redirect> ListRedirects()
        {
            return _repository.ListRedirects(_currentPortal.PortalID);
        }
        public Redirect GetGlobalRedirect(string oldURL)
        {
            return _repository.GetGlobalRedirect(oldURL);
        }
        public Redirect GetRedirect(string oldURL)
        {
            var portal = _cacheService.GetCurrentPortal();
            return _repository.GetRedirect(oldURL, portal);
        }
        public bool EditRedirect(Redirect redirectToEdit)
        {
            var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();
            redirectToEdit.Portal = portalRepository.GetPortal(_currentPortal.PortalID);

            // Validation logic
            if (!ValidateRedirect(redirectToEdit))
                return false;

            // Database logic
            try
            {
                _repository.EditRedirect(redirectToEdit);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }

        public bool CreateRedirect(Redirect redirectToCreate)
        {
            if (redirectToCreate.Portal == null)
            {
                var portalRepository = ServiceLocator.Current.GetInstance<IPortalRepository>();
                redirectToCreate.Portal = portalRepository.GetPortal(_currentPortal.PortalID);
            }
            // Validation logic
            if (!ValidateRedirect(redirectToCreate))
                return false;

            // Database logic
            try
            {
                _repository.CreateRedirect(redirectToCreate);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(GeneralMethods.GetStackNames(), ex);
                return false;
            }
            return true;
        }
        #endregion

    }
}